package studyguide.ch11;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * Game midlet with layout manager. Character is not moved for the sake of simplicity
 * @author Eduardo Ferreira
 */
public class LayerManagerMidlet extends MIDlet {

	private static final int NUM_COLUMS = 10;
	private static final int NUM_ROWS = 10;
	private static final int STEP_SIZE = 5;
	
	private final Command exitCommand;
	private final Display display;
	private GameTask gameTask;
	
	private final MyGameCanvas gameCanvas;
	private final Graphics graphics;
	private final Sprite mainSprite;
	private final TiledLayer background;
	private final TiledLayer maze;
	private final LayerManager layerManager;
	
	private class SampleCommandListener implements CommandListener {
		public void commandAction(Command command, Displayable displayable) {
			if (command == exitCommand) {
				destroyApp(true);
				notifyDestroyed();
			} else {
				throw new RuntimeException("UNKNOWN COMMAND" + command);
			}
		}
	}
	
	private class GameTask extends TimerTask {
		public void run() {
			gameLoop();
		}
	}
	
	public LayerManagerMidlet() throws IOException {
		// Create the game objects
		gameCanvas = new MyGameCanvas();
		graphics = gameCanvas.getGraphics();
		layerManager = new LayerManager();
		Image bgImage = Image.createImage("/game/background.png");
		Image mazeImage = Image.createImage("/game/brick.png");
		mainSprite = new Sprite(Image.createImage("/game/sprite.png"), 20, 32);
		background = new TiledLayer(NUM_COLUMS, NUM_ROWS, bgImage, bgImage.getWidth(), bgImage.getHeight());
		// mazeImage.getWidth() / 3 because we have 3 tiles on the image
		maze = new TiledLayer(NUM_COLUMS, NUM_ROWS, mazeImage, mazeImage.getWidth() / 3, mazeImage.getHeight());
		
		// Configure the tiled layers' grid
		background.fillCells(0, 0, NUM_COLUMS, NUM_ROWS, 1);
		maze.fillCells(0, 0, NUM_COLUMS, 1, 1);
		maze.fillCells(0, 0, 1, NUM_ROWS, 1);
		maze.fillCells(NUM_COLUMS-1, 0, 1, NUM_ROWS, 1);
		maze.fillCells(0, NUM_ROWS-1, NUM_COLUMS, 1, 1);

		// Set the sprite at 1/4 of the scenario
		mainSprite.defineReferencePixel(mainSprite.getWidth()/2, mainSprite.getHeight()/2);
		mainSprite.setRefPixelPosition(maze.getWidth()/4, maze.getHeight()/4);
		
		// Assemble the displayable
		exitCommand = new Command("Exit", Command.EXIT, 1);
		gameCanvas.addCommand(exitCommand);
		SampleCommandListener listener = new SampleCommandListener();
		gameCanvas.setCommandListener(listener);
		display = Display.getDisplay(this);
		
		// Assemble layer manager
		layerManager.append(mainSprite);
		layerManager.append(maze);
		layerManager.append(background);
	}
	
	protected void destroyApp(boolean unconditional) {
		gameTask.cancel();
	}

	protected void pauseApp() {
		gameTask.cancel();
	}

	protected void startApp() throws MIDletStateChangeException {
		display.setCurrent(gameCanvas);
		// Start the game loop
		Timer timer = new Timer();
		gameTask = new GameTask();
		timer.schedule(gameTask, 0, 1000/30); // 30 frames per second
	}

	protected void gameLoop() {
		// Clear screen 
		graphics.setColor(0x00ffffff);
		graphics.fillRect(0, 0, gameCanvas.getWidth(), gameCanvas.getHeight());
		
		// Move the characted
		int keyState = gameCanvas.getKeyStates();
		if ((keyState & GameCanvas.DOWN_PRESSED) > 0) {
			mainSprite.move(0, STEP_SIZE);
			if (mainSprite.collidesWith(maze, false)) {
				mainSprite.move(0, -STEP_SIZE);	
			}
		}
		if ((keyState & GameCanvas.UP_PRESSED) > 0) {
			mainSprite.move(0, -STEP_SIZE);
			if (mainSprite.collidesWith(maze, false)) {
				mainSprite.move(0, +STEP_SIZE);	
			}
		}
		if ((keyState & GameCanvas.LEFT_PRESSED) > 0) {
			mainSprite.move(-STEP_SIZE, 0);
			if (mainSprite.collidesWith(maze, false)) {
				mainSprite.move(+STEP_SIZE, 0);	
			}
		}
		if ((keyState & GameCanvas.RIGHT_PRESSED) > 0) {
			mainSprite.move(STEP_SIZE, 0);
			if (mainSprite.collidesWith(maze, false)) {
				mainSprite.move(-STEP_SIZE, 0);	
			}
		}
		
		// Check for "scroll" on the map
		int distanceXFromHalf = mainSprite.getRefPixelX() - gameCanvas.getWidth()/2; 
		if (distanceXFromHalf > 0) {
			if (distanceXFromHalf + gameCanvas.getWidth() > maze.getWidth()) {
				distanceXFromHalf = maze.getWidth() - gameCanvas.getWidth();
			}
		} else {
			distanceXFromHalf = 0;
		}
		int distanceYFromHalf = mainSprite.getRefPixelY() - gameCanvas.getWidth()/2; 
		if (distanceYFromHalf > 0) {
			if (distanceYFromHalf + gameCanvas.getHeight() > maze.getHeight()) {
				distanceYFromHalf = maze.getHeight() - gameCanvas.getHeight();
			}
		} else {
			distanceYFromHalf = 0;
		}
		layerManager.setViewWindow(
				distanceXFromHalf, distanceYFromHalf, 
				gameCanvas.getWidth(), gameCanvas.getHeight());
		
		// Paint the layer manager at the upper-left corner:
		layerManager.paint(graphics, 0, 0);
		
		// Flush to output
		gameCanvas.flushGraphics();
	}
	
}
